using System;

namespace WindowsPhone.CompactContainer.ServiceLocation.CompactContainer
{

    /// <summary>
    /// 
    /// </summary>
    public interface IContainer : IDisposable
    {
        /// <summary>
        /// Gets the components.
        /// </summary>
        /// <value>The components.</value>
        ComponentCollection Components { get; }

        /// <summary>
        /// Gets the singleton instance count.
        /// </summary>
        /// <value>The singleton instance count.</value>
        int SingletonInstanceCount { get; }

        /// <summary>
        /// Gets the default handler.
        /// </summary>
        /// <value>The default handler.</value>
        DefaultHandler DefaultHandler { get; set; }

        /// <summary>
        /// Determines whether the specified service has component.
        /// </summary>
        /// <param name="service">The service.</param>
        /// <returns>
        /// 	<c>true</c> if the specified service has component; otherwise, <c>false</c>.
        /// </returns>
        bool HasComponent(Type service);
        
        /// <summary>
        /// Determines whether the specified key has component.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the specified key has component; otherwise, <c>false</c>.
        /// </returns>
        bool HasComponent(string key);
        
        /// <summary>
        /// Resolves the specified service.
        /// </summary>
        /// <param name="service">The service.</param>
        /// <returns></returns>
        object Resolve(Type service);

        /// <summary>
        /// Resolves the component for the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        object Resolve(string key);

        /// <summary>
        /// Resolves the component for the type
        /// </summary>
        /// <typeparam name="T">The type to resolve</typeparam>
        /// <returns></returns>
        T Resolve<T>() where T: class;

        /// <summary>
        /// Resolves the component for the type and key
        /// </summary>
        /// <typeparam name="T">The type to resolve</typeparam>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        T Resolve<T>(string key) where T: class;

        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="classType">Type of the class.</param>
        void AddComponent(string key, Type classType);

        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="classType">Type of the class.</param>
        /// <param name="lifestyle">The lifestyle.</param>
        void AddComponent(string key, Type classType, LifestyleType lifestyle);

        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="classType">Type of the class.</param>
        void AddComponent(string key, Type serviceType, Type classType);

        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="classType">Type of the class.</param>
        /// <param name="lifestyle">The lifestyle.</param>
        void AddComponent(string key, Type serviceType, Type classType, LifestyleType lifestyle);

        /// <summary>
        /// Adds the component instance.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="instance">The instance.</param>
        void AddComponentInstance(string key, object instance);

        /// <summary>
        /// Adds the component instance.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="instance">The instance.</param>
        void AddComponentInstance(string key, Type serviceType, object instance);
        
        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <typeparam name="TClass">The type of the class.</typeparam>
        /// <param name="lifestyle">The lifestyle.</param>
        void AddComponent<TService, TClass>(LifestyleType lifestyle) where TClass : TService;

        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <typeparam name="TClass">The type of the class.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="lifestyle">The lifestyle.</param>
        void AddComponent<TService, TClass>(string key, LifestyleType lifestyle) where TClass : TService;


        /// <summary>
        /// Adds the component.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <typeparam name="TClass">The type of the class.</typeparam>
        /// <param name="key">The key.</param>
        void AddComponent<TService, TClass>(string key) where TClass : TService;

        void RemoveComponent<TService>();

        /// <summary>
        /// Adds the component instance.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <param name="instance">The instance.</param>
        void AddComponentInstance<TService>(object instance);

        /// <summary>
        /// Replaces the component instance.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <param name="instance">The instance.</param>
        void ReplaceComponentInstance<TService>(object instance);

        /// <summary>
        /// Gets the services.
        /// </summary>
        /// <param name="serviceType">Type of the service.</param>
        /// <returns></returns>
        object[] GetServices(Type serviceType);

        /// <summary>
        /// Gets the services.
        /// </summary>
        /// <typeparam name="T">The types to find</typeparam>
        /// <returns></returns>
        T[] GetServices<T>();

        /// <summary>
        /// Registers the handler.
        /// </summary>
        /// <param name="targetType">Type of the target.</param>
        /// <param name="handler">The handler.</param>
        void RegisterHandler(Type targetType, IHandler handler);

        /// <summary>
        /// Registers the handler.
        /// </summary>
        /// <typeparam name="T">The type to register the handler against</typeparam>
        /// <param name="handler">The handler.</param>
        void RegisterHandler<T>(IHandler handler);
    }
}